import React, { Component } from 'react'
import PropTypes from "prop-types"
import { View, ColorPropType, StyleSheet, Animated, Easing, PanResponder } from 'react-native'
import Color from '../../config/theme/standard/color';

class Switch extends Component {

    constructor(props, context) {
        super(props, context)
        const { width, height, isOpen, size } = props;

        this.offset = width - height;
        this.handlerSize = height - 1;
        if (size == 'small') {
            this.offset = 40 - 24;
            this.handlerSize = 24 - 1;
        }
        this._panResponder = PanResponder.create({
            onStartShouldSetPanResponder: (evt, gestureState) => true,
            onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
            onMoveShouldSetPanResponder: (evt, gestureState) => true,
            onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
            onPanResponderTerminationRequest: (evt, gestureState) => true,
            onPanResponderGrant: this._onPanResponderGrant,
            onPanResponderMove: this._onPanResponderMove,
            onPanResponderRelease: this._onPanResponderRelease
        })

        this.state = {
            prevPropsValue: isOpen,
            value: isOpen,
            toggleable: true,
            alignItems: isOpen ? 'flex-end' : 'flex-start',
            handlerAnimation: new Animated.Value(this.handlerSize),
            switchAnimation: new Animated.Value(isOpen ? size == 'small' ? 2 : 1 : 0)
        }
    }

    static getDerivedStateFromProps(nextProps, prevState) {
        if (('isOpen' in nextProps) && nextProps.isOpen != prevState.prevPropsValue) {
            return {
                prevPropsValue: nextProps.isOpen,
                value: nextProps.isOpen,
                alignItems: nextProps.isOpen ? 'flex-end' : 'flex-start',
                switchAnimation: new Animated.Value(nextProps.isOpen ? nextProps.size == 'small' ? 2 : 1 : 0)
            }
        }
        return null;
    }

    componentDidUpdate(prevProps) {
        if (typeof this.props.value !== 'undefined' && this.props.value !== this.state.value) {
            this.toggleSwitch(true)
        }
    }

    _onPanResponderGrant = (evt, gestureState) => {
        const { disabled } = this.props;
        if (disabled) return;

        this.animateHandler(this.handlerSize * 6 / 5) //动效
    };

    _onPanResponderMove = (evt, gestureState) => {
        const { value } = this.state;
        const { disabled } = this.props;
        if (disabled) return;

        this.setState({
            toggleable: value ? (gestureState.dx < 10) : (gestureState.dx > -10)
        })
    };

    _onPanResponderRelease = (evt, gestureState) => {
        const { toggleable, value } = this.state;
        const { disabled, onAsyncPress, onValueChange, isOperate } = this.props;

        if (disabled) return;

        if (toggleable) {
            if (onValueChange) {
                if (isOperate) {
                    this.toggleSwitch(true, onValueChange);
                } else {
                    let flag = onValueChange();
                    this.toggleSwitch(flag);
                }

            }
        } else {
            this.animateHandler(this.handlerSize)
        }
    };

    toggleSwitch = (result, callback = () => null) => { // result of async
        const { value, switchAnimation } = this.state;
        const { size } = this.props;
        const toValue = !value;

        this.animateHandler(this.handlerSize);
        if (result) {
            this.animateSwitch(toValue, () => {
                callback(toValue);
                this.setState({
                    value: toValue,
                    alignItems: toValue ? 'flex-end' : 'flex-start'
                });
                switchAnimation.setValue(toValue ? size == 'small' ? 2 : 1 : 0)
            })
        }
    };

    animateSwitch = (value, callback = () => null) => {
        const { switchAnimation } = this.state;

        Animated.timing(switchAnimation,
            {
                toValue: value ? this.offset : -this.offset,
                duration: 150,
                easing: Easing.linear
            }
        ).start(callback)
    };

    animateHandler = (value, callback = () => null) => {
        const { handlerAnimation } = this.state;

        Animated.timing(handlerAnimation,
            {
                toValue: value,
                duration: 150,
                easing: Easing.linear
            }
        ).start(callback)
    };

    render() {
        const { switchAnimation, handlerAnimation, alignItems, value } = this.state;
        const {
            backgroundActive, backgroundInactive, size,
            width, height, circleColorActive, circleColorInactive, style,
            circleStyle, shadowColor, disabledColor, disabledCircleBorder, NABackgroundColor,
            ...rest
        } = this.props;
        let normalWidth;
        let normalHieght;
        if (size == 'small') {
            normalWidth = 40;
            normalHieght = 24;
        } else {
            normalWidth = width;
            normalHieght = height;
        }

        const interpolatedBackgroundColor = switchAnimation.interpolate({
            inputRange: value ? [-this.offset, 1] : [0, this.offset],
            outputRange: [backgroundInactive, backgroundActive]
        });

        const disabledBackgroundColor = switchAnimation.interpolate({
            inputRange: value ? [-this.offset, 1] : [0, this.offset],
            outputRange: [disabledColor, NABackgroundColor]
        });

        const interpolatedCircleColor = switchAnimation.interpolate({
            inputRange: value ? [-this.offset, 1] : [0, this.offset],
            outputRange: [circleColorInactive, circleColorActive]
        });

        const disabledCircleColor = switchAnimation.interpolate({
            inputRange: value ? [-this.offset, 1] : [0, this.offset],
            outputRange: [disabledColor, disabledColor]
        });

        const interpolatedBorderColor = switchAnimation.interpolate({
            inputRange: value ? [-this.offset, 1] : [0, this.offset],
            outputRange: [shadowColor, backgroundActive]
        });

        const disabledBorderColor = switchAnimation.interpolate({
            inputRange: value ? [-this.offset, 1] : [0, this.offset],
            outputRange: [disabledColor, NABackgroundColor]
        });

        const disabledCircleBorderColor = switchAnimation.interpolate({
            inputRange: value ? [-this.offset, 1] : [0, this.offset],
            outputRange: [disabledCircleBorder, '#A3A3A3']
        });


        return (

            <View style={styles.view}>
                <Animated.View
                    {...rest}
                    {...this._panResponder.panHandlers}
                    style={[styles.container, {
                        width: normalWidth, height: normalHieght,
                        alignItems,
                        borderRadius: normalHieght / 2,
                        backgroundColor: this.props.disabled ? disabledBackgroundColor : interpolatedBackgroundColor,
                        borderWidth: 1,
                        borderColor: this.props.disabled ? disabledBorderColor : interpolatedBorderColor,
                    }]}>
                    <Animated.View style={{
                        backgroundColor: this.props.disabled ? disabledCircleColor : interpolatedCircleColor,
                        width: handlerAnimation,
                        height: this.handlerSize,
                        borderRadius: size == 'small' ? 24 / 2 : height / 2,
                        transform: [{ translateX: switchAnimation }],
                        borderWidth: 1,
                        borderColor: this.props.disabled ? disabledCircleBorderColor : interpolatedBorderColor,
                        elevation: 1,
                        //IOS阴影
                        shadowOffset: { width: 1, height: 1 },
                        shadowOpacity: 0.5,
                        shadowRadius: 2,
                        shadowColor: shadowColor,
                    }} />
                </Animated.View>
            </View>
        )
    }
}

const styles = StyleSheet.create({
    view: {
        paddingRight: 15,
    },
    container: {
        overflow: 'hidden',
        justifyContent: 'center',
        paddingRight: 1,
    }
});

Switch.propTypes = {
    width: PropTypes.number,
    height: PropTypes.number,
    disabled: PropTypes.bool,
    //开关初始状态，默认为关闭
    isOpen: PropTypes.bool,
    //是否可以正常打开或者关闭
    isOperate: PropTypes.bool,
    circleColorActive: ColorPropType,
    circleColorInactive: ColorPropType,
    //可用状态下开启时的颜色
    backgroundActive: ColorPropType,
    //可用状态下关闭时的颜色 
    backgroundInactive: ColorPropType,
    shadowColor: ColorPropType,
    disabledColor: ColorPropType,
    //关闭不可用状态下圆圈的颜色
    disabledCircleBorder: ColorPropType,
    //不可用状态下开启时的颜色
    NABackgroundColor: ColorPropType,
    onValueChange: PropTypes.func,
    size: PropTypes.string
};

Switch.defaultProps = {
    width: 53,
    height: 32,
    isOpen: false,
    isOperate: true,
    disabled: false,
    circleColorActive: Color.white,
    circleColorInactive: Color.white,
    backgroundActive: Color.switch.backgroundActive,
    backgroundInactive: Color.white,
    disabledColor: Color.switch.disabledColor,
    disabledCircleBorder: Color.switch.disableCircleBorder,
    shadowColor: Color.switch.shadow,
    NABackgroundColor: Color.switch.naBackgroundColor,
    size: 'normal'
};

export default Switch
